package com.tim.helper.analysis.xssd;

import cn.hutool.core.map.MapBuilder;
import com.tim.util.FileUtils;
import com.tim.util.UnicodeChineseUtil;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author
 * @Title:
 * @Package
 * @date 2022/9/30 23:43
 * @Description:
 */
public class MqAnalysisHelper {
    /**
     * 检索消息监听器
     *
     * 懒猪
     * exodus   ctx
     * 猪耳朵
     * exodus_pigear   ctx
     * 每日说
     * xqxc ctx
     * xqxc ext
     *
     */
    Map<String, List<String>> topicListeners=new HashMap<>();// topic listener(listener,groupId,key) map
    Map<String, List<String>> listenerTags=new HashMap<>();// listener tags map

    ElePropHandler propHandler = new ElePropHandler();
    XmlBeanHandler xmlBeanHandler = new XmlBeanHandler();
    @Test
    public void searchXssdMqListener() throws Exception{
        /* 读取xqxc_dev.properties；组装Properties、注释Map
         * 遍历文件夹；读取项目 setting.conf、ctx.xml文件，替换占位符
         * xml解析，获取bean处理
         *
         */
        String projectPath = "E:\\gitlab\\xqxc"; // 项目路径
        String ctxFileSuf = "ctx.xml,ext.xml";// bean配置文件后缀，大小写不敏感
        String settingFileSuf = "setting.conf";// setting文件后缀，大小写不敏感
        String configDirPath = "/src/main/resources/config";// 项目配置文件路径
        String xqxcDevPath = projectPath+"\\settings\\dev\\xqxc-dev.properties";// 全局配置文件
        projectPath = projectPath+"/";// 子级文件夹；可不填
        int printTopicVar = Constant.HAS_KEY;
        String pomFileName = "pom.xml";

        propHandler.initDefaultProps(xqxcDevPath);
        xmlBeanHandler.propHandler = propHandler;
        StringBuilder builder = new StringBuilder();

        // 遍历文件夹
        Files.walkFileTree(Paths.get(projectPath), new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs)
                    throws IOException
            {
                /* step1，初次过滤，必须有pom.xml文件、config文件夹*/
                File subDir = path.toFile();
//                System.out.println(subDir.getAbsolutePath());
                // 必须有pom文件、config文件夹
                File[] files = subDir.listFiles(f -> f.getName().contains(pomFileName));
                if(files!=null && files.length>1){
                    return FileVisitResult.CONTINUE;
                }
                File configDir = new File(subDir.toString()+configDirPath);
                if(!configDir.exists()){
                    return FileVisitResult.CONTINUE;
                }

                /* step2，找到settingFileSuf、ctxFileSuf文件；读取settingFileSuf，替换占位符*/
                // 找到文件，无时返回
                File[] settingFiles = configDir.listFiles(f -> f.getName().toLowerCase().contains(settingFileSuf));
                File[] ctxFiles = configDir.listFiles(f -> StringUtils.containsAny(f.getName().toLowerCase(), ctxFileSuf.split(",")));
                if(settingFiles==null || settingFiles.length==0){
                    return FileVisitResult.CONTINUE;// 无指定文件，直接返回
                }
                if(ctxFiles==null || ctxFiles.length==0){
                    // 无bean配置文件，检索其他文件夹
                    File ctxConfigDir = new File(configDir.getAbsolutePath()+"/plat");
                    if(ctxConfigDir.exists() && ctxConfigDir.isDirectory()){
                        ctxFiles = ctxConfigDir.listFiles(f -> {
                            String fileName = f.getName().toLowerCase();
//                            System.out.println(fileName);
                            return StringUtils.containsAny(f.getName().toLowerCase(), ctxFileSuf.split(","));
                        });
                    }
                    if(ctxFiles==null || ctxFiles.length==0){
                        return FileVisitResult.CONTINUE;// 无指定文件，默认直接返回
                    }
                }

                String projectName = path.getName(path.getNameCount()-1).toString();
                // 读取settingFileSuf，替换占位符
                propHandler.initProjectProps(settingFiles);

                /* step3，dom4j读取ctxFileSuf；解析mqConfig、listener；拼接显示*/
                try {
                    List<Element> beanElements = xmlBeanHandler.getElementList(ctxFiles[0], "bean");
                    // beanId-groupId
                    Map<String,String> beanGroupMap = xmlBeanHandler.handleMqConfigBeans(beanElements);
                    if(beanGroupMap.isEmpty()){
                        return FileVisitResult.CONTINUE;// 无mq配置，默认直接返回
                    }
                    // groupId-listenerTopics(listener;[key topics]逗号分隔)
                    Map<String, List<String>> groupListeners = xmlBeanHandler.handleListenerBeans(beanElements, beanGroupMap, printTopicVar);

                    handleTopicListenerMap(groupListeners);
                    handleListenerTagsMap(path.toString(), groupListeners);
                    // 拼接显示
//                    System.out.println(groupListeners);
                    generateProjectMqInfo(projectName, beanGroupMap, groupListeners, builder);

                } catch (DocumentException e) {
                    e.printStackTrace();
                }


                return FileVisitResult.CONTINUE;
            }
        });
//        System.out.println(String.format("\t{\n%s\n\t}\n", builder));

        String topicMap =
                topicListeners.keySet().stream()
                        .map(
                                key -> {
                                    List<String> list = topicListeners.get(key);
                                    Collections.sort(list);
                                    String str = list.stream()
                                            .map(e->{
                                                String listener = e.substring(0, e.indexOf(" l"));
                                                String tags = listenerTags.get(listener).stream().collect(Collectors.joining(Constant.TOPIC_SPLITOR));
                                                return String.format("\t\t\t//%s\n%s", tags, e);
                                            })
                                            .collect(Collectors.joining("\n"));

                                    return String.format("\t\t// %s，%s\n{\n%s\n}\n", key, propHandler.getPropertiesComment(key), str);
                                })
                        .collect(Collectors.joining("\n"));
        System.out.println(String.format("\t{\n%s\n\t}\n", topicMap));
    }

    private void handleTopicListenerMap(Map<String, List<String>> groupListeners){
        groupListeners.forEach(
                (groupId, list) -> {
                    for (String str : list) {
                        int index = str.indexOf(Constant.LISTENER_SPLITOR);
                        if(index<0){
                            continue;
                        }
                        String listener = str.substring(0, index);
                        String[] split = str.substring(index + 1)
                                .trim().split("[\\s,]+");
                        for (int i = 0; i+1 < split.length; i+=2) {
                            String propKey = split[i];
                            String topic = split[i + 1];
                            if (!topicListeners.containsKey(topic)) {
                                topicListeners.put(topic, new ArrayList<>());
                            }
                            List<String> list1 = topicListeners.get(topic);
                            list1.add(String.format("%s l%s;//%s，%s", listener, list1.size()+1, groupId, propKey));
                        }
                    }
                });
    }

    private void handleListenerTagsMap(String dir, Map<String, List<String>> groupListeners) throws FileNotFoundException {
        List<String> reduce = groupListeners.values()
                .stream()
                .reduce((o, n) -> {
                    o.addAll(n);
                    return o;
                }).orElse(Collections.emptyList());
        for(String listenerTopic : reduce){
            String listener = listenerTopic.substring(0, listenerTopic.indexOf(Constant.LISTENER_SPLITOR)).trim();
            if(listenerTags.containsKey(listener)){
                continue;
            }
            List<String> tagList = new ArrayList<>();
            String path = dir + "/src/main/java/" + listener.replaceAll("\\.", "/") + ".java";
            CompilationUnit cu = JavaParser.parse(new File(path));
            List<Node> childNodes = cu.getChildNodes();
            for(Node node : childNodes.get(childNodes.size()-1).getChildNodes()){
                if(node instanceof FieldDeclaration){
                    NodeList<AnnotationExpr> annotations = ((FieldDeclaration) node).getAnnotations();
                    for(AnnotationExpr annoExpr : annotations){
//                        System.out.println(annoExpr.getName());
                        if("Value".equals(annoExpr.getName().asString())){
                            String memberValue = ((SingleMemberAnnotationExpr) annoExpr).getMemberValue().toString();
                            if(memberValue.replaceAll("[\"\\s]", "").toLowerCase().contains("tag}")){
                                tagList.add(propHandler.getPropertiesValue(memberValue, Constant.NO_KEY));
                            }
//                        System.out.println(memberValue);
                        }
                    }
                }
            }
            listenerTags.put(listener, tagList);
        }

    }

    @Test
    public void printSettingConf() throws Exception {
        String projectPath = "E:\\gitlab\\xqxc"; // 项目路径
        String settingFileSuf = "setting.conf";// setting文件后缀，大小写不敏感
        String configDirPath = "/src/main/resources/config";// 项目配置文件路径
        String xqxcDevPath = projectPath+"\\settings\\dev\\xqxc-dev.properties";// 全局配置文件
        projectPath = projectPath+"/";// 子级文件夹；可不填
        String pomFileName = "pom.xml";

        propHandler.initDefaultProps(xqxcDevPath);
        StringBuilder builder = new StringBuilder();

        Files.walkFileTree(
                Paths.get(projectPath),
                new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs)
                            throws IOException {
                        /* step1，初次过滤，必须有pom.xml文件、config文件夹*/
                        File subDir = path.toFile();
                        //                System.out.println(subDir.getAbsolutePath());
                        // 必须有pom文件、config文件夹
                        File[] files = subDir.listFiles(f -> f.getName().contains(pomFileName));
                        if (files != null && files.length > 1) {
                            return FileVisitResult.CONTINUE;
                        }
                        File configDir = new File(subDir.toString() + configDirPath);
                        if (!configDir.exists()) {
                            return FileVisitResult.CONTINUE;
                        }

                        /* step2，找到settingFileSuf、ctxFileSuf文件；读取settingFileSuf，替换占位符*/
                        // 找到文件，无时返回
                        File[] settingFiles =
                                configDir.listFiles(f -> f.getName().toLowerCase().contains(settingFileSuf));
                        if (settingFiles == null || settingFiles.length == 0) {
                            return FileVisitResult.CONTINUE; // 无指定文件，直接返回
                        }

                        // 读取settingFileSuf，替换占位符
                        propHandler.initProjectProps(settingFiles);
                        String projectName = path.getName(path.getNameCount() - 1).toString();
                        //                System.out.println(projectName);
                        System.out.println("\n======="+projectName+"=======\n");
                        Properties projectProps = propHandler.projectProps;
                        projectProps.keySet().stream().sorted().forEach(k->{
                            String keyStr = k.toString();
                            String valStr = projectProps.getProperty(keyStr);
                            if(keyStr.startsWith("mq.") && !valStr.contains("http:") && valStr.contains("_")){
                                System.out.println(keyStr +"="+ valStr);
                            }
                        });

                        return FileVisitResult.CONTINUE;
                    }
                });
    }

    interface Constant {
        int HAS_KEY = 1;
        int NO_KEY = 0;
        String LISTENER_SPLITOR = "；";
        String TOPIC_SPLITOR = "，";
    }

    class ElePropHandler {
        private Properties defaultProps;
        public Properties projectProps;
        Map<String, String> defaultValueCommentMap;// key-注释 map
        Map<String, String> projectValueCommentMap;// key-注释 map

        void initDefaultProps(String defaultPropPath) throws IOException {
            defaultProps = new Properties();
            defaultProps.load(new FileInputStream(defaultPropPath));
            defaultValueCommentMap = getValueCommentMap(new File(defaultPropPath));// key-注释 map
            initManualRecord(defaultPropPath);
        }

        /**手动记录 topic-注释*/
        private void initManualRecord(String projectPath) throws IOException {
            String[] split = projectPath.split("[/\\\\]+");
            String project = split[split.length - 1];
            MapBuilder<String, String> builder = MapBuilder.<String, String>create();
            if("exodus".equals(project)){
                builder.put("BIZPIG_MESSAGE_TOPIC", "推送消息topic")
                        .put("REPORT_EXPORT_STATUS_TOPIC", "报表状态更新topic")
                        .put("MICROEP_RECONCILIATION_REPORT_TOPIC", "导出微企对账单")
                        .put("REPORT_EXPORT_STATUS_TOPIC", "报表状态更新topic")
                        .put("FADADA_TOPIC", "法大大topic。tag：实名认证成功，签署成功")
                        .put("ALIPHONE_UNBIND_TOPIC", "虚拟号解绑")
                        .put("RIDER_ASSIGN_TOPIC", "派单消息")
                        .put("RIDER_HEARTBEAT_TOPIC", "骑士心跳消息。tag：骑士丢失心跳")
                        .put("DELIVERY_STATUS_TOPIC", "配送单消息topic")
                        .put("ORDER_STATUS_TOPIC", "订单状态topic")
                        .put("BIZPIG_MESSAGE_TOPIC", "推送消息topic")
                        .put("SETTLE_ORDER_STATUS_TOPIC", "结算消息topic")
                        .put("SETTLE_ORDER_STATUS_TOPIC", "订单状态")
                        .put("SETTLE_ORDER_NOTIFY_TOPIC", "结算通知MQ-TOPIC")
                        .put("SETTLE_ORDER_SPLIT_NOTIFY_TOPIC", "结算分账通知MQ-TOPIC")
                        .put("SETTLE_ORDER_FLOW_TOPIC", "结算订单变动MQ-TOPIC")
                        .put("ALIPHONE_UNBIND_TOPIC", "虚拟号解绑")
                        .put("REPORT_EXPORT_APPLY_TOPIC", "报表导出消息")
                        .put("REPORT_EXPORT_STATUS_TOPIC", "报表状态更新topic")
                        .put("DELIVERY_STATUS_TOPIC", "配送单消息。tag：DeliveryTagEnum")
                        .put("SETTLE_ORDER_STATUS_TOPIC", "结算消息topic")
                        .put("DELIVERY_STATUS_TOPIC", "配送单消息topic")
                        .put("ORDER_STATUS_TOPIC", "订单状态topic")
                        .put("SETTLE_ORDER_STATUS_TOPIC", "结算消息topic")
                        .put("PLAT_RECONCILIATION_TOPIC", "对账主表通知消息")
                        .put("REPORT_EXPORT_RECORD_TOPIC", "报表记录通知消息")
                        .put("PAY_HANDLE_ORDER_SPLIT_TOPIC", "处理配送订单-结算完成分账消息")
                        .put("PAY_HANDLE_ORDER_SPLIT_TOPIC", "处理配送订单-结算完成分账消息。未到转账时间，延迟转账")
                        .put("PLAT_PAY_TOPIC", "支付平台topic。tag：订单支付成功、查询退款状态、退款状态变更")
                        .put("PLAT_PAY_TOPIC", "支付平台topic。银联钱包开通成功")
                        .put("MICROEP_RECONCILIATION_TOPIC", "对账主表通知消息")
                        .put("REPORT_EXPORT_RECORD_TOPIC", "报表记录通知消息")
                        .put("MICROEP_CHARGE_TOPIC", "计费主题")
                        .put("MICROEP_ACCOUNT_RIDER_TOPIC", "微企骑士消息")
                        .put("", "")
                ;
            }
            else if("exodus_pigear".equals(project)){
                builder.put("", "")
                        .put("", "")
                ;

            }
            else if("xqxc".equals(project)){
                builder.put("PAYMENT_STATUS_CHANGE", "支付单状态变化");
                builder.put("REFUND_STATUS_CHANGE", "退款单状态变化");
                builder.put("REMIT_STATUS_CHANGE", "汇款单状态变化");
                builder.put("CONFIRM_STATUS_CHANGE", "确认单状态变化");
                builder.put("MIS_EARNINGS_TOPIC", "虚拟支付单状态变化");
                builder.put("FIX_IOS_RECHARGE", "修复ios充值单消息");
                builder.put("MERCHANT_APP_PAYMENT_STATUS_CHANGE", "商户APP支付单状态变化");
                builder.put("MERCHANT_APP_REFUND_STATUS_CHANGE", "商户APP退款单状态变化");
                builder.put("HOTEL_ORDER_REFUND_STATUS_CHANGE", "酒店订单退款单状态变化");
                builder.put("YUMS_WITHDRAWAL","提现TOPIC消息");
                builder.put("YUMS_RECHARGE_STATUS_CHANGE","充值订单状态变更消息");
                builder.put("SUPPLIER_BALANCE_PAY_TOPIC","供应商余额支付TOPIC消息");
                builder.put("SUPPLIER_WITHDRAWAL_STATUS_TOPIC","供应商提现状态变化TOPIC消息");
                builder.put("PAYMENT_STATUS_CHANGE", "支付单状态变化");
                builder.put("REFUND_STATUS_CHANGE", "退款单状态变化");
                builder.put("REMIT_STATUS_CHANGE", "汇款单状态变化");
                builder.put("CONFIRM_STATUS_CHANGE", "确认单状态变化");
                builder.put("SHOW_MESSAGE_TOPIC", "秀场模块消息");
                builder.put("USER_MESSAGE_TOPIC", "用户模块消息");
                builder.put("MERCHANT_MESSAGE_TOPIC", "商户模块消息");
                builder.put("ORDER_STATUS_TOPIC", "订单模块消息");
                builder.put("STARVALUE_RULE_PERIOD_CHANGE","结算模块");
                builder.put("SERVERS_GATHER_BEANS", "赠送能量值相关topic");
                builder.put("QIANG_PAI_TOPIC", "抢拍活动消息topic");
                builder.put("VAS_GIFT_TOPIC", "买赠活动topic");
                builder.put("MARKETING_SETTLE_TOPIC", "营销结算topic");
                builder.put("MERCHANT_REGIST_TOPIC","商户注册topic");
                builder.put("FEN_LAI_SUPPLIER_TOPIC","纷来消息topic");
                builder.put("DELIVERY_ORDER_STATUS_TOPIC","同城骑手配送单相关消息");
                builder.put("RIDER_BIND_GETUI_TOPIC","个推相关");
                builder.put("UNIONPAY_MERCHANT_STATUS_TOPIC","union merchant status");
                builder.put("RIDER_JIANGFA_TOPIC","奖罚模块");
                builder.put("DELIVER_MESSAGE_TOPIC","配送平台TOPIC");
                builder.put("SMALL_SHOP_GOODS_DEL_TOPIC","删除微店商品topic");
                builder.put("ORDER_SETTLE_SUCCESS_TOPIC","结算服务");
                builder.put("ACTIVITY_POINTS_LOTTERY_TOPIC","积分夺宝开奖消息");
                builder.put("REPORT_EXPORT_APPLY_TOPIC","申请导出报表");
                builder.put("ORDER_DELAYS_QUEUE_TOPIC","订单延迟MQ");
                builder.put("MERCHANT_REGIST_TOPIC","订单延迟MQ");
                builder.put("MERCHANT_REGIST_TOPIC","订单延迟MQ");
                builder.put("SCHEDULED_SEND_MESSAGE", "定时任务");
                builder.put("ORDER_AFTER_SALE_TOPIC", "订单售后mq");
                builder.put("REWARD_STATUS_CHANGE_TOPIC", "奖惩规则状态变更");
                builder.put("INTEGRAL_ORDER_STATUS_TOPIC", "积分订单状态");
                builder.put("ACCOUNT_BALANCE_CHANGE", "账户余额变化");
                builder.put("SETTLE_DELAY_TOPIC", "结算延时消息");
                builder.put("RECHARGE_STATUS_CHANGE", "充值状态变化消息");
                builder.put("SHOWRICE_LIMIT_CHANGE", "信用值额度修改");
                builder.put("MIS_EARNINGS_DELAYS_TOPIC", "增值订单延迟消息TOPIC");
                builder.put("MIS_EARNINGS_TOPIC", "增值订单结算TOPIC");
                builder.put("UNIONPAY_PAYMENT_RECORD_STATUS_TOPIC", "银联支付状态");
                builder.put("MERCHANT_ENTERING_PLAT_AUDIT_SUCCESS_MQTOPIC", "商户入驻改造平台审核成功");
                builder.put("REPORT_EXPORT_STATUS_TOPIC", "报表状态更新");
                builder.put("ACCOUNT_USER_REG_FINISHED", "用户注册完成");
                builder.put("INCOME_CALCULATE_TOPIC", "结算补贴计算消息");
                builder.put("FADADA_SIGN_SUCCESS_MQTOPIC", "法大大Topic");
                builder.put("GIFT_USER_MESSAGE_TOPIC", "礼屋消息TOPIC");
                builder.put("YUMS_UPLOAD_IMG", "上传图片到通联");
                builder.put("MERCHANT_EXPORT_TOPIC", "商户导出");
                builder.put("DELIVERY_ORDER_DELAY_TOPIC", "配送单延迟MQ");
                builder.put("OPERATE_LOG_NOTIFY", "order_operate_log  ");
                builder.put("REQUIREMENT_OVERTIME_TOPIC", "需求单超时MQ");
                builder.put("MIS_XIUDOU_ORDER_TOPIC", "股票订单topic");
                builder.put("EVENT_NOTIFY", "事件消息TOPIC");
                builder.put("WAREHOUSE_GOODS_TOPIC", "延时下架售罄批发商品topic");
                builder.put("HOTEL_ORDER_TOPIC", "酒店订单TOPIC");
                builder.put("GOODS_STATUS_CHANGE_TOPIC", "商品状态变更消息topic");
                builder.put("CITY_IM_HEARTBEAT_TOPIC", "骑士心跳");
                builder.put("THIRD_SUPPLIER_TOPIC", "第三方topic");
                builder.put("REWARD_RULE_END_TOPIC", "奖惩规则通知结算topic");
                builder.put("OUTER_GOODS_TOPIC", "第三方消息topic");
                builder.put("AUTOMATIC_PAY_TOPIC", "自动打款消息体");

            }
            defaultValueCommentMap.putAll(builder.build());
        }

        void initProjectProps(File[] settingFiles) throws IOException {
            projectProps = new Properties();
            File settingFile = settingFiles[0];
            projectProps.load(new FileInputStream(settingFile));
            projectProps.forEach((k,v)->{
                if(v.toString().contains("$")){
//                        System.out.println(k+"="+v);
                    String value = getPropertiesValue(v.toString(), Constant.NO_KEY);
                    projectProps.setProperty(k.toString(), value);
                }
            });
            projectValueCommentMap = getValueCommentMap(settingFile);// key-注释 map
        }

        String getPropertiesValue(String key, int hasKey){
            if(StringUtils.isBlank(key)){
                return key;
            }
            key = key.replaceAll("[\\$\\{\\}\"]", "").trim();
            int index = key.indexOf(":");
            if(index>0){
                // 处理<value>${mq.customer.show.mqTopic}:${mq.customer.show.mqTopic.tags}</value>
                key = key.substring(index+1).trim();
            }
            String value = projectProps.containsKey(key) ? projectProps.getProperty(key)
                    : defaultProps.containsKey(key) ? defaultProps.getProperty(key) : key;
            return hasKey==Constant.NO_KEY ? value : key+"\t"+value;
        }

        String getPropertiesComment(String value){
            if(StringUtils.isBlank(value)){
                return value;
            }
            String[] split = value.split("\t");
            value = split.length==1 ? split[0] : split[1];
            value = value.replaceAll("[\\$\\{\\}]", "").trim();
            String result = projectValueCommentMap.containsKey(value) && StringUtils.isNotBlank(projectValueCommentMap.get(value)) ? projectValueCommentMap.get(value)
                    : defaultValueCommentMap.containsKey(value) ? defaultValueCommentMap.get(value) : "";

            return result;
        }

        // key-注释 map
        private Map<String, String> getValueCommentMap(File file){
            List<String> list = null;
            try {
                String fileCharsetName = FileUtils.getFileCharsetName(file.getAbsolutePath());
                list = Files.readAllLines(file.toPath(), Charset.forName(fileCharsetName));
            } catch (IOException e) {
                e.printStackTrace();
            }
            Map<String, String> valueCommentMap = new HashMap<>();
            if(CollectionUtils.isNotEmpty(list)){
                String comment = "";
                for (int i = 0; i < list.size(); i++) {
                    String line = list.get(i).trim();
                    if(StringUtils.isBlank(line)){
                        continue;
                    }else if(line.startsWith("#")){
                        // 注释行
                        comment = line.substring(1).trim().replaceAll("^#", "");

                    }else if(line.contains("=")){
                        // 属性行
                        int index = line.indexOf("=");
                        String value = line.substring(index + 1).trim();
                        index = value.indexOf("#");
                        if(index>0){
                            comment = index>0 ? value.substring(index + 1) : comment;
                            value = value.substring(0, index).trim();
                        }
                        if(comment.trim().contains("\\u")){
                            // unicode转汉字
                            comment = UnicodeChineseUtil.unicodeDecode(comment);
//                      System.out.println(comment);
                        }
                        valueCommentMap.put(value, comment);
                        comment = "";
                    }
                }
            }

            return valueCommentMap;
        }

    }

    class XmlBeanHandler {
        ElePropHandler propHandler;

        List<Element> getElementList(File ctxFile, String name) throws DocumentException {
            SAXReader xmlReader = new SAXReader();
            Document ctxDocument = xmlReader.read(ctxFile);
            List<Element> beanElements = ctxDocument.getRootElement().elements(name);
            return beanElements;
        }

        // beanId-groupId
        private Map<String,String> handleMqConfigBeans(List<Element> beanElements) {
            Map<String,String> beanGroupMap = new HashMap<>();// beanId-groupId
            for(Element beanElement : beanElements){
                String aClass = beanElement.attributeValue("class");
                if(aClass!=null && aClass.contains("RocketMqConfig")){
                    // mq配置
                    String groupId = getElePropValue(beanElement, "groupId");
                    groupId = propHandler.getPropertiesValue(groupId, Constant.NO_KEY);
                    if(StringUtils.isNotBlank(groupId)){
                        beanGroupMap.put(beanElement.attributeValue("id"), groupId);
                    }
//                            System.out.println(groupId);
                }
            }
            return beanGroupMap;
        }

        // groupId-listenerTopics(listener;[key topics]逗号分隔)
        private Map<String, List<String>> handleListenerBeans(List<Element> beanElements, Map<String, String> beanGroupMap, int printTopicVar) {
            Map<String, List<String>> groupListeners = new HashMap<>();// groupId-listenerTopics(listener;topics逗号分隔)
            for(Element beanElement : beanElements){
                String aClass = beanElement.attributeValue("class");
                // mq监听器
                if(aClass!=null && aClass.contains("RewriteRocketMqMessgeSuscriber")){
                    String groupId = "",classFullName="", topics="";
                    for(Object obj : beanElement.elements("property")){
                        Element beanPropEle = (Element) obj;
                        String propName = beanPropEle.attributeValue("name");
                        if("mqConfig".equals(propName)){
                            String mqConfigBeanId = beanPropEle.attributeValue("ref");
                            if(StringUtils.isBlank(mqConfigBeanId)){
                                // listener中配置mq 配置bean
                                groupId = beanPropEle.element("bean").element("property").attributeValue("value");
                                groupId = propHandler.getPropertiesValue(groupId, Constant.NO_KEY);
                            }else{
                                groupId = beanGroupMap.get(mqConfigBeanId);
                            }
                        }else if("messageListener".equals(propName)){
                            // 获取listener类型
                            classFullName=beanPropEle.element("bean").attributeValue("class");
                        }else if("topic".equals(propName)){
                            List<Element> elements = beanPropEle.element("array").elements("value");
                            for(Element e : elements){
                                String text = e.getText();
                                topics += propHandler.getPropertiesValue(text, printTopicVar)+Constant.TOPIC_SPLITOR;
                            }
                        }
                    }
//                            System.out.println(topic);
                    if(!groupListeners.containsKey(groupId)){
                        groupListeners.put(groupId, new ArrayList<>());
                    }
                    List<String> list = groupListeners.get(groupId);
                    list.add(classFullName+Constant.LISTENER_SPLITOR+topics);

                }
            }
            return groupListeners;
        }

        String getElePropValue(Element element, String pName){
            String value = (String) element.elements("property").stream()
                    .filter(e -> pName.equals(((Element) e).attributeValue("name")))
                    .findFirst()
                    .map(e -> ((Element) e).attributeValue("value"))
                    .orElse("NULL");
            return value;
        }
    }
    private void generateProjectMqInfo(String projectName, Map<String,String> beanGroupMap, Map<String, List<String>> groupListeners, StringBuilder builder) {
        int num = 1;
        StringBuilder groupListenerBuilder = new StringBuilder();
        Set<String> groupIdSet = groupListeners.keySet();
        String projectGroups = beanGroupMap.values().stream()
                .map(groupId->"\t\t// "+groupId+" "+propHandler.getPropertiesComment(groupId))
                .collect(Collectors.joining("\n"));
        for(String groupId : groupIdSet){
            if(groupIdSet.size()>1){
                // 多个groupId，展示
                groupListenerBuilder.append("\t\t// groupId：").append(groupId)
                        .append(" ").append(propHandler.getPropertiesComment(groupId))
                        .append("\n");
            }
            for(String listener : groupListeners.get(groupId)){
                String[] strs = listener.split(Constant.LISTENER_SPLITOR);// listenerTopics(listener；topics逗号分隔)
                String topicInfo = Arrays.stream(strs[1].split(Constant.TOPIC_SPLITOR))
                        .map(topic->"\t\t// "+topic+" "+propHandler.getPropertiesComment(topic))
                        .collect(Collectors.joining("\n"));
                groupListenerBuilder.append(String.format(groupListenerTemplate, topicInfo, strs[0], num++));
            }

        }
        builder.append(String.format(groupTemplate, projectName, projectGroups, groupListenerBuilder));
    }


    String groupTemplate =
            "        // %1$s项目groupId：\n%2$s\n"
                    + "        {\n"
                    + "            // topic枚举；项目中的topic写到一个枚举\n"
                    + "\n"
                    + "%3$s\n"
                    + "        }\n\n";
    String groupListenerTemplate = "      %1$s\n" +
            "            %2$s l%3$s;// \n\n";
}
